package com.fitz.serializer;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author fitz
 * Created  on 2020/6/8
 */
public class KryoSerializer implements Serializer {

    @Override
    public byte getSerializerType() {
        return SerializerType.KRYO;
    }

    @Override
    public <T> byte[] serialize(T t) {
        Kryo kryo = kryoLocal.get();
        ByteArrayOutputStream byteArrayOutputStream = null;
        Output output = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            output = new Output(byteArrayOutputStream);
            kryo.writeClassAndObject(output, t);
            return byteArrayOutputStream.toByteArray();
        }finally {
            assert output != null;
            output.close();
            try {
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            kryoLocal.remove();
        }
    }

    @Override
    public <T> T deSerialize(Class<T> clazz, byte[] bytes) {
        Kryo kryo = kryoLocal.get();
        ByteArrayInputStream byteArrayInputStream = null;
        Input input = null;
        try {
            byteArrayInputStream = new ByteArrayInputStream(bytes);
            input = new Input(byteArrayInputStream);
            return (T) kryo.readClassAndObject(input);
        }finally {
            assert input != null;
            input.close();
            try {
                byteArrayInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            kryoLocal.remove();
        }
    }

    private static final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>(){
        @Override
        protected Kryo initialValue() {
            Kryo kryo = new Kryo();
            kryo.setReferences(true);
            kryo.setRegistrationRequired(false);
            return kryo;
        }
    };
}
